#include "simulation_manager.h"
#include "ns3/log.h"
#include "ns3/config.h"
#include "ns3/double.h"
#include "ns3/string.h"
#include "ns3/simulator.h"
#include <filesystem>
#include <iostream>
#include <iomanip>
#include <sstream>

namespace ns3 {

NS_LOG_COMPONENT_DEFINE("SimulationManager");

SimulationManager::SimulationManager() 
  : m_currentVehicleId(0),
    m_simulationDuration(3600), // 默认模拟时长为3600秒
    m_resultsDir("/home/xixi/SAGIN/ns-allinone-3.42/ns-3.42/scratch/simulation/results")
{
  NS_LOG_FUNCTION(this);
}

SimulationManager::~SimulationManager() 
{
  NS_LOG_FUNCTION(this);
}

bool SimulationManager::Initialize() 
{
  NS_LOG_FUNCTION(this);
  
  // 清理旧的普通性能文件（非详细文件）
  CleanupOldPerformanceFiles();
  
  // 初始化各个管理器
  if (!m_dataManager.Initialize()) {
    NS_LOG_ERROR("数据管理器初始化失败");
    return false;
  }

  // 从数据管理器获取所有车辆ID
  m_vehicleIds = m_dataManager.GetAllVehicleIds();
  if (m_vehicleIds.empty()) {
    NS_LOG_ERROR("未找到任何车辆数据");
    return false;
  }
  
  NS_LOG_INFO("找到 " << m_vehicleIds.size() << " 辆车");
  
  // 设置模拟参数
  SetupSimulationParameters();
  
  return true;
}

void SimulationManager::Run() 
{
  NS_LOG_FUNCTION(this);

  // 确保结果目录存在
  std::filesystem::create_directories(m_resultsDir);
  
  std::cout << "\n=============================================" << std::endl;
  std::cout << "    空天地一体化车联网仿真系统启动" << std::endl;
  std::cout << "    发现 " << m_vehicleIds.size() << " 辆车需要模拟" << std::endl;
  std::cout << "=============================================" << std::endl;
  
  auto startTime = std::chrono::high_resolution_clock::now();
  
  // 为每个车辆运行单独的模拟
  size_t completedVehicles = 0;
  for (uint32_t vehicleId : m_vehicleIds) {
    auto vehicleStartTime = std::chrono::high_resolution_clock::now();
    
    m_currentVehicleId = vehicleId;
    NS_LOG_INFO("开始模拟车辆 " << vehicleId);
    
    // 运行当前车辆模拟
    RunSimulationForVehicle(vehicleId);
    
    // 清理当前模拟，准备下一次模拟
    CleanupSimulation();
    
    // 统计完成情况
    completedVehicles++;
    auto vehicleEndTime = std::chrono::high_resolution_clock::now();
    auto vehicleDuration = std::chrono::duration_cast<std::chrono::seconds>(vehicleEndTime - vehicleStartTime).count();
    
    std::cout << "\n进度: " << completedVehicles << "/" << m_vehicleIds.size() 
              << " (" << std::fixed << std::setprecision(1) 
              << (100.0 * completedVehicles / m_vehicleIds.size()) << "%)" << std::endl;
    std::cout << "车辆 " << vehicleId << " 的模拟用时: " << vehicleDuration << " 秒" << std::endl;
    
    if (completedVehicles < m_vehicleIds.size()) {
      // 预估剩余时间
      auto elapsedTime = std::chrono::high_resolution_clock::now() - startTime;
      auto elapsedSeconds = std::chrono::duration_cast<std::chrono::seconds>(elapsedTime).count();
      double avgTimePerVehicle = static_cast<double>(elapsedSeconds) / completedVehicles;
      size_t remainingVehicles = m_vehicleIds.size() - completedVehicles;
      int estimatedRemainingSeconds = static_cast<int>(avgTimePerVehicle * remainingVehicles);
      
      int remainingHours = estimatedRemainingSeconds / 3600;
      int remainingMinutes = (estimatedRemainingSeconds % 3600) / 60;
      int remainingSeconds = estimatedRemainingSeconds % 60;
      
      std::cout << "预计剩余时间: ";
      if (remainingHours > 0) {
        std::cout << remainingHours << "小时 ";
      }
      std::cout << remainingMinutes << "分 " << remainingSeconds << "秒" << std::endl;
    }
  }
  
  auto endTime = std::chrono::high_resolution_clock::now();
  auto totalDuration = std::chrono::duration_cast<std::chrono::seconds>(endTime - startTime).count();
  
  std::cout << "\n=================================================" << std::endl;
  std::cout << "    空天地一体化车联网仿真系统 - 完成报告" << std::endl;
  std::cout << "=================================================" << std::endl;
  std::cout << "总计模拟内容:" << std::endl;
  std::cout << "- 车辆数量: " << m_vehicleIds.size() << " 辆" << std::endl;
  std::cout << "- 地面基站数量: " << m_nodeManager.GetGroundStationNodes().GetN() << " 个" << std::endl;
  std::cout << "- 卫星数量: " << m_nodeManager.GetSatelliteNodes().GetN() << " 个" << std::endl;
  std::cout << "- 模拟总时长: " << m_simulationDuration << " 秒/车辆" << std::endl;
  std::cout << "\n性能统计:" << std::endl;
  std::cout << "- 结果文件保存在: " << m_resultsDir << std::endl;
  std::cout << "- 每个车辆生成详细CSV性能数据" << std::endl;
  std::cout << "\n运行时间信息:" << std::endl;
  std::cout << "- 总运行时间: " << (totalDuration / 3600) << "小时 " 
            << ((totalDuration % 3600) / 60) << "分 " 
            << (totalDuration % 60) << "秒" << std::endl;
  std::cout << "- 平均每辆车用时: " << (totalDuration / m_vehicleIds.size()) << " 秒" << std::endl;
  std::cout << "- 开始时间: " << GetTimeString(startTime) << std::endl;
  std::cout << "- 结束时间: " << GetTimeString(endTime) << std::endl;
  std::cout << "=================================================" << std::endl;
  
  NS_LOG_INFO("所有模拟完成");
}

uint32_t SimulationManager::GetCurrentVehicleId() const 
{
  return m_currentVehicleId;
}

void SimulationManager::RunSimulationForVehicle(uint32_t vehicleId) 
{
  NS_LOG_FUNCTION(this << vehicleId);
  
  // 控制台实时输出 - 开始车辆模拟
  std::cout << "\n=========================================" << std::endl;
  std::cout << "开始为车辆 " << vehicleId << " 运行模拟 (" 
            << (std::find(m_vehicleIds.begin(), m_vehicleIds.end(), vehicleId) - m_vehicleIds.begin() + 1) 
            << "/" << m_vehicleIds.size() << ")" << std::endl;
  std::cout << "=========================================" << std::endl;
  
  // 显示一些模拟的基本设置
  std::cout << "模拟设置:" << std::endl;
  std::cout << "- 模拟持续时间: " << m_simulationDuration << " 秒" << std::endl;
  std::cout << "- 结果保存目录: " << m_resultsDir << std::endl;
  std::cout << "- 地面基站覆盖范围: 3500 米" << std::endl;
  std::cout << "- 卫星连接干扰率: 5%-15%" << std::endl;
  
  // 初始化节点管理器
  m_nodeManager.Initialize(m_dataManager);
  
  // 设置当前车辆节点
  m_nodeManager.SetupVehicleNode(vehicleId);
  
  // 设置地面基站节点
  m_nodeManager.SetupGroundStationNodes();
  
  // 设置卫星节点
  m_nodeManager.SetupSatelliteNodes();
  
  // 设置节点的网络协议栈
  m_nodeManager.InstallInternetStack();

  // 初始化链接管理器
  m_linkManager.Initialize(m_nodeManager);
  
  // 设置车辆与地面基站的WIFI连接
  m_linkManager.SetupWifiConnections();
  
  // 设置车辆与卫星的P2P连接
  m_linkManager.SetupSatelliteConnections();
  
  // 分配IP地址
  m_linkManager.AssignIpAddresses();
  
  // 设置应用程序
  m_linkManager.SetupApplications();
  
  // 初始化数据收集器
  m_dataCollector.Initialize(m_dataManager, m_nodeManager, m_linkManager);
  
  // 启动FlowMonitor
  m_dataCollector.SetupFlowMonitor();
  
  // 运行模拟
  NS_LOG_INFO("正在运行车辆 " << vehicleId << " 的模拟...");
  std::cout << "运行车辆 " << vehicleId << " 的模拟 (持续时间: " << m_simulationDuration << "秒)..." << std::endl;
  
  // 添加进度事件
  for (int progress = 10; progress <= 100; progress += 10) {
    double progressTime = m_simulationDuration * progress / 100.0;
    Simulator::Schedule(Seconds(progressTime), 
                       &SimulationManager::PrintSimulationProgress, 
                       this, vehicleId, progress);
  }
  
  Simulator::Stop(Seconds(m_simulationDuration));
  Simulator::Run();
  
  // 收集并保存性能数据
  std::cout << "模拟完成，正在收集性能数据..." << std::endl;
  m_dataCollector.CollectData();
  
  std::cout << "正在保存车辆 " << vehicleId << " 的详细性能数据..." << std::endl;
  m_dataCollector.SaveData(vehicleId, m_resultsDir);
  std::cout << "数据保存完成。" << std::endl;
}

void SimulationManager::SetupSimulationParameters() 
{
  NS_LOG_FUNCTION(this);
  
  // 设置模拟时长
  Config::SetDefault("ns3::OnOffApplication::PacketSize", UintegerValue(1472));
  Config::SetDefault("ns3::OnOffApplication::DataRate", StringValue("100kb/s"));
}

void SimulationManager::PrepareNextSimulation() 
{
  NS_LOG_FUNCTION(this);
  // 重置各管理器，准备下一次模拟
}

void SimulationManager::CleanupSimulation() 
{
  NS_LOG_FUNCTION(this);
  
  // 重置模拟器
  Simulator::Destroy();
  
  // 重置各管理器
  m_nodeManager.Reset();
  m_linkManager.Reset();
  m_dataCollector.Reset();
}

void SimulationManager::PrintSimulationProgress(uint32_t vehicleId, int percentage)
{
  std::cout << "车辆 " << vehicleId << " 的模拟进度: " << percentage << "% 完成" << std::endl;
  
  if (percentage % 25 == 0) {  // 每25%输出一次连接状态摘要
    // 输出当前连接状态摘要
    std::cout << "  --> 当前连接摘要:" << std::endl;
    
    // 地面基站连接数
    int groundStationCount = m_linkManager.GetGroundStationConnections().size();
    int connectedGSCount = 0;
    
    // 检查已连接的地面基站
    for (const auto& entry : m_linkManager.GetGroundStationConnections()) {
      double distance = entry.second.distance;
      if (distance <= 3500) {  // 根据前面分析3500m是连接阈值
        connectedGSCount++;
      }
    }
    
    std::cout << "      - 地面基站: " << groundStationCount << " 个 (约 " 
              << connectedGSCount << " 个在连接范围内)" << std::endl;
    
    // 卫星连接数
    int satelliteCount = m_linkManager.GetSatelliteConnections().size();
    std::cout << "      - 卫星: " << satelliteCount << " 个" << std::endl;
    
    // 总用时估计
    int remainingSeconds = m_simulationDuration * (100 - percentage) / 100;
    int remainingMinutes = remainingSeconds / 60;
    remainingSeconds %= 60;
    std::cout << "      - 预计剩余时间: " << remainingMinutes << " 分 " << remainingSeconds << " 秒" << std::endl;
    
    if (percentage == 100) {
      std::cout << "\n  --> 模拟完成! 正在准备性能统计数据..." << std::endl;
    }
  }
}

void SimulationManager::CleanupOldPerformanceFiles()
{
  NS_LOG_FUNCTION(this);
  
  // 确保结果目录存在
  if (!std::filesystem::exists(m_resultsDir)) {
    return; // 如果目录不存在，无需清理
  }
  
  std::cout << "检查旧的性能文件..." << std::endl;
  
  // 寻找并删除所有普通性能文件（非详细文件）
  int removedFiles = 0;
  for (const auto& entry : std::filesystem::directory_iterator(m_resultsDir)) {
    std::string filename = entry.path().filename().string();
    
    // 检查是否为普通性能文件（以vehicle_开头，以_performance.csv结尾，但不含detailed）
    if (filename.find("vehicle_") == 0 && filename.find("_performance.csv") != std::string::npos 
        && filename.find("_detailed_") == std::string::npos) {
      std::filesystem::remove(entry.path());
      removedFiles++;
    }
  }
  
  if (removedFiles > 0) {
    NS_LOG_INFO("已清理 " << removedFiles << " 个旧的普通性能文件");
    std::cout << "已删除 " << removedFiles << " 个旧的普通性能文件" << std::endl;
  } else {
    std::cout << "没有发现需要清理的旧性能文件" << std::endl;
  }
}

std::string SimulationManager::GetTimeString(const std::chrono::time_point<std::chrono::high_resolution_clock>& timePoint) const
{
  auto timeT = std::chrono::high_resolution_clock::to_time_t(timePoint);
  std::stringstream ss;
  ss << std::put_time(std::localtime(&timeT), "%Y-%m-%d %H:%M:%S");
  return ss.str();
}

} // namespace ns3
